#include <cmath>      //abs
#include <algorithm>  //max
#include <cassert>

float EPSILON = 0.0001f;
float MAX_REL_ERR = 0.001f;
unsigned int MAX_ULPS = 5;

bool fpCompareAbsError(const float lhs, const float rhs, const float epsilon)
{
  float err = std::abs(lhs - rhs);
  return (err <= epsilon);
}

bool fpCompareRelError(const float lhs, const float rhs, const float max_relative_err)
{
  if (lhs == rhs) //avoid 0/0
    return true;

  float rel_err = (std::abs(lhs - rhs) / std::max(lhs, rhs));


  return rel_err <= max_relative_err;
}

bool fpCompareULPs(const float lhs, const float rhs, const unsigned int max_ulps)
{
  if(lhs == rhs)
    return true;
  //different signs are not equal (except 0 and -0)
  if ( (lhs < 0) != (rhs < 0) )
    return false;

  int ulps = int(lhs) - int(rhs);
  return (std::abs(ulps) <= max_ulps);
}

bool fpCompareCombo(const float lhs, const float rhs,
  const float max_relative_err, const float max_absolute_err,
  const unsigned int max_ulps)
{
  return (fpCompareAbsError(lhs, rhs, max_absolute_err)
          || fpCompareRelError(lhs, rhs, max_relative_err)
          || fpCompareULPs(lhs, rhs, max_ulps));
}

